﻿/**************************************************************
 *
 * 唯一标识：e30e4e87-77b7-46c3-8c3f-bd193c51df81
 * 命名空间：Microsoft.Extensions.DependencyInjection
 * 创建时间：2023/7/24 10:54:21
 * 机器名称：DESKTOP-S0D075D
 * 创建者：antho
 * 电子邮箱：fengqinhua2016@163.com
 * 描述：
 *
 **************************************************************/

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Logging;
using Sgr;
using Sgr.Algorithm;
using Sgr.Application;
using Sgr.Application.Queries;
using Sgr.AuditLogs.Services;
using Sgr.Caching.Services;
using Sgr.Data;
using Sgr.DataCategories.Services;
using Sgr.DataCategories.Stores;
using Sgr.DistributedLock;
using Sgr.Domain.Entities.Auditing;
using Sgr.Domain.Uow;
using Sgr.EventBus;
using Sgr.Exceptions;
using Sgr.Generator;
using Sgr.Identity.Services;
using Sgr.Licence.Services;
using Sgr.Notifications.Services;
using Sgr.OmniMetrics.Services;
using Sgr.Organizations;
using Sgr.Security.Tokens.Services;
using Sgr.Security.VerifyCode;
using Sgr.Trackers;
using Sgr.Utilities;
using System.Diagnostics.CodeAnalysis;

namespace Microsoft.Extensions.DependencyInjection
{
    /// <summary>
    /// 扩展
    /// </summary>
    public static class ServiceCollectionExtensions
    {
        /// <summary>
        /// 注册集成事件处理器。
        /// 默认：同一事件类型下，防止同一处理器类型被重复注册（多次调用不会产生重复执行）。
        /// 如果需要强制重复注册（不建议），将 preventDuplicate 设为 false。
        /// </summary>
        /// <typeparam name="T">集成事件消息类型</typeparam>
        /// <typeparam name="TH">处理器实现类型</typeparam>
        /// <param name="services">服务集合</param>
        /// <returns></returns>
        public static IServiceCollection AddIntegrationEventHandler<T, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TH>(
            this IServiceCollection services)
            where T : IntegrationEvent
            where TH : class, IIntegrationEventHandler<T>
        {
            // 集成事件契约标识
            var key = IntegrationEventTypes.ResolveTypeName<T>();

            //// TryAddKeyedTransient 对于相同的 服务类型 + 键 组合，只会注册第一个实现，无法满足当前场景需要
            //services.TryAddKeyedTransient<IIntegrationEventHandler, TH>(key);
            //var exists = services.Where(sd => sd.ServiceType == typeof(IIntegrationEventHandler));

            if (!services.Any(descriptor => descriptor.ServiceType == typeof(IIntegrationEventHandler)
                 && Equals(descriptor.ServiceKey, key)
                 && descriptor.KeyedImplementationType == typeof(TH)))
            {
                // 如果不存在，才进行注册
                services.AddKeyedTransient<IIntegrationEventHandler, TH>(key);

                // 注册集成事件类型
                IntegrationEventTypes.RegisterType(key, typeof(T));
            }

            return services;
        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="services"></param>
        /// <returns></returns>
        public static IServiceCollection AddSgrCore(this IServiceCollection services)
        {
            //配置Id生成器
            services.AddOptions<SnowflakeOption>()
                .BindConfiguration("Sgr:Snowflake")
                .Configure(opt =>
                {
                    if (int.TryParse(EnvironmentHelper.GetEnvironmentVariable("SGR_SNOWFLAKE_DATACENTERID"), out int datacenterId))
                        opt.DatacenterId = datacenterId;

                    if (int.TryParse(EnvironmentHelper.GetEnvironmentVariable("SGR_SNOWFLAKE_MACHINEID"), out int machineid))
                        opt.MachineId = machineid;

                    if (opt.DatacenterId < 0)
                        opt.DatacenterId = 0;

                    if (opt.DatacenterId > 31)
                        opt.DatacenterId = 31;

                    if (opt.MachineId < 0)
                        opt.MachineId = 0;

                    if (opt.MachineId > 31)
                        opt.MachineId = 31;
                });

            services.TryAddSingleton<IStringIdGenerator, DefaultStringIdGenerator>();
            services.TryAddSingleton<INumberIdGenerator, DefaultNumberIdGenerator>();
            services.TryAddSingleton<ISegmentNumIdGenerator, DefaultSegmentNumIdGenerator>();

            //数据字典
            services.TryAddSingleton<ICategoryTypeService, DefaultCategoryTypeService>();

            //签名验证工具
            services.TryAddSingleton<ISignatureChecker, DefaultSignatureChecker>();

            //配置审计接口
            services.TryAddSingleton<IAuditedOperator, DefaultAuditedOperator>();
            services.TryAddScoped<IAuditLogService, DefaultAuditLogService>();

            //认证相关
            services.TryAddTransient<IPasswordHashService, Md5PasswordHashService>();
            services.TryAddScoped<IAccountAuthService, NoAccountAuthService>();
            services.TryAddScoped<ITokenBlacklistService, NoTokenBlacklistService>();
            services.TryAddScoped<IVerifyCodeService, DefaultVerifyCodeService>();
            //services.AddTransient<IPermissionChecker, PermissionChecker>();

            //缓存
            services.TryAddSingleton<ICacheManager, NoCacheManager>();
            services.TryAddScoped<ICategoryItemsQuery, DefalutCategoryItemsQuery>();
            services.TryAddScoped<ICategoryItemsManagement, DefaultCategoryItemsManagement>();
            services.TryAddScoped<IAdmDivManagement, DefaultAdmDivManagement>();

            services.TryAddSingleton<IDataDictionaryStore, DefaultLocalDataDictionaryStore>();
            services.TryAddSingleton<IAdmDivStore, DefaultLocalAdmDivStore>();

            // 幂等
            services.TryAddScoped<IMessageMark, MessageMarkByMemory>();
            services.TryAddScoped<IMessageToken, MessageTokenByMemory>();

            // 集成事件
            services.TryAddScoped<IEventBus, NullEventBus>();

            // 通知服务
            services.TryAddScoped<INotificationService, DefaultNotificationService>();

            //本地使用的锁(限单机使用)
            services.TryAddSingleton<IDistributedLock, LocalDistributedLock>();

            //算法
            services.TryAddTransient<IConsistentHash, DefaultConsistentHash>(); //一致性Hash算法的默认实现

            // 请求路由上下文
            services.TryAddScoped<IRequestRouteContext, RequestRouteContext>();

            //工作单元
            services.AddUow();

            //查询服务
            services.TryAddScoped<ISgrQueryContext, NoReadDbContext>();

            //安全相关
            services.TryAddScoped<ITemporaryTokenService, DefaultTemporaryTokenService>();

            //许可证管理
            services.TryAddSingleton<IAppLicenseManage, AppLicenseManage>();
            services.TryAddSingleton<IActivationCodeGenerator, ActivationCodeGenerator>();

            //异常处理
            services.TryAddEnumerable(ServiceDescriptor.Singleton<IExceptionHandler, DomainExceptionHandler>());

            // OmniMetric 数据服务接口
            services.TryAddScoped<IOmniMetricService, DefaultOmniMetricService>();

            // 组织用户提供者的空实现
            services.TryAddScoped<IOrganizationProvider, NullIOrganizationProvider>();
            services.TryAddScoped<IUserProvider, NullUserProvider>();

            return services;
        }

        public static IServiceCollection AddUow(this IServiceCollection services)
        {
            services.AddOptions<UnitOfWorkOption>()
               .BindConfiguration("Sgr:UnitOfWork")
               .PostConfigure(opt =>
               {
                   opt.IsolationLevel ??= System.Data.IsolationLevel.ReadCommitted;
                   opt.Timeout ??= 30000;
               });

            services.TryAddTransient<IUnitOfWork, DefaultUnitOfWork>();

            services.TryAddSingleton<IUnitOfWorkManager, DefaultUnitOfWorkManager>();
            services.TryAddSingleton<IUnitOfWorkTracker, DefaultUnitOfWorkTracker>();

            return services;
        }

        /// <summary>
        /// 仅用于启动时读取 IConfiguration。IConfiguration 是单例且不依赖 ServiceProvider，
        /// 因此即使 ServiceProvider 被释放，返回的实例仍然有效。
        /// </summary>
        public static IConfiguration GetConfiguration(this IServiceCollection services)
        {
            using var sp = services.BuildServiceProvider();
            return sp.GetRequiredService<IConfiguration>();
        }
    }
}